package net.monare.mifss.admin.ui.win;

import com.vaadin.server.ThemeResource;
import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.ui.*;
import com.vaadin.ui.themes.Runo;
import net.monare.mifss.MifssAdminMainUI;
import net.monare.mifss.MifssMessages;
import net.monare.mifss.admin.ui.comp.ApiKeyUiLink;
import net.monare.mifss.admin.ui.comp.PoolDefUiLink;
import net.monare.mifss.admin.ui.comp.StorageDefUiLink;
import net.monare.mifss.admin.ui.mod.StorageDefUiModule;
import net.monare.mifss.configurations.pojo.ApiKey;
import net.monare.mifss.configurations.pojo.ContentPoolDef;
import net.monare.mifss.configurations.pojo.StorageDef;
import net.monare.mifss.configurations.pojo.StorageSetDef;
import net.monare.mifss.evn.*;
import net.monare.mifss.lib.AppContext;
import net.monare.mifss.services.StorageService;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.context.SecurityContext;

import java.util.Collections;
import java.util.List;

@org.springframework.stereotype.Component
@Scope("prototype")
public class ConfigureStorageWindow extends Window {

    private static final long serialVersionUID = 5372967117146561880L;

    @Autowired
    private transient ApplicationContext applicationContext;
    @Autowired
    private transient AuthenticationManager authenticationManager;

    private Logger logger = Logger.getLogger(ConfigureStorageWindow.class);

    private VerticalLayout leftPane;
    private VerticalLayout middlePane;
    private List<StorageDef> storageDefList;
    private List<StorageSetDef> storageSetDefList;
    private StorageDef currentStorageDef;
    private Accordion accordion;

    public ConfigureStorageWindow() {

        resetLeftPane();
        resetMiddlePane(null);

        storageDefList = null;

        setCaption(MifssMessages.getMessage("tile.configure.storage"));
        setStyleName(Runo.WINDOW_DIALOG);

        HorizontalSplitPanel mainPanel = new HorizontalSplitPanel();
        mainPanel.setSizeFull();
        mainPanel.setSplitPosition(360, Unit.PIXELS);

        mainPanel.setFirstComponent(leftPane);
        mainPanel.setSecondComponent(middlePane);

        setWidth("1000px");
        setHeight("95%");

        setModal(true);

        setContent(mainPanel);

    }

    public void resetMiddlePane(StorageDef storageDef) {

        if (middlePane == null) {

            middlePane = new VerticalLayout();
            middlePane.setSpacing(true);
            middlePane.setMargin(true);

        } else {
            middlePane.removeAllComponents();
        }

        if (storageDef != null) {

            currentStorageDef = storageDef;

            Label rpTitle = new Label(MifssMessages.getMessage("tile.configure.storage"));
            rpTitle.setStyleName(Runo.LABEL_H1);
            middlePane.addComponent(rpTitle);

            Label horizontalSeparator3 = new Label("<hr/>", ContentMode.HTML);
            middlePane.addComponent(horizontalSeparator3);

            HorizontalLayout actionBar = new HorizontalLayout();
            actionBar.setSpacing(true);
            NativeButton addNewPoolDef = new NativeButton(MifssMessages.getMessage("button.add.new.pool"));
            addNewPoolDef.setWidth("190px");
            addNewPoolDef.addClickListener(new ConfigureSelectedPoolListener(this, null));
            actionBar.addComponent(addNewPoolDef);

            NativeButton addNewApiKey = new NativeButton(MifssMessages.getMessage("button.add.new.key"));
            addNewApiKey.setWidth("190px");
            addNewApiKey.addClickListener(new ConfigureSelectedApiKeyListener(this, null));
            actionBar.addComponent(addNewApiKey);

            middlePane.addComponent(actionBar);

            Label horizontalSeparator4 = new Label("<hr/>", ContentMode.HTML);
            middlePane.addComponent(horizontalSeparator4);

            Label storageDefLabel = new Label(MifssMessages.getMessage("tile.storage.definition"));
            storageDefLabel.setStyleName(Runo.LABEL_H2);
            middlePane.addComponent(storageDefLabel);

            //
            // add storage definition UI module
            StorageDefUiModule sdModule = new StorageDefUiModule(storageDef);
            sdModule.protectFields();

            middlePane.addComponent(sdModule);

            NativeButton updateStorageButton = new NativeButton(MifssMessages.getMessage("button.update.storage"));
            updateStorageButton.addClickListener(new UpdateStorageDefinitionListener(sdModule, this));
            updateStorageButton.setWidth("190px");

            middlePane.addComponent(updateStorageButton);
            Label horizontalSeparator1 = new Label("<hr/>", ContentMode.HTML);
            middlePane.addComponent(horizontalSeparator1);

            //
            // pool definition
            Label poolDefLabel = new Label(MifssMessages.getMessage("tile.pool.definitions"));
            poolDefLabel.setStyleName(Runo.LABEL_H2);
            middlePane.addComponent(poolDefLabel);

            for (ContentPoolDef cpd : storageDef.getContentPoolDefs()) {
                PoolDefUiLink poolLink = new PoolDefUiLink(cpd, this);
                middlePane.addComponent(poolLink);

            }

            Label horizontalSeparator2 = new Label("<hr/>", ContentMode.HTML);
            middlePane.addComponent(horizontalSeparator2);

            //
            // api key definition
            Label apiKeyDefLabel = new Label(MifssMessages.getMessage("tile.api.key.definitions"));
            apiKeyDefLabel.setStyleName(Runo.LABEL_H2);
            middlePane.addComponent(apiKeyDefLabel);

            for (ApiKey apiKey : storageDef.getApiKeys()) {
                ApiKeyUiLink apiKeyLink = new ApiKeyUiLink(apiKey, this, storageDef.getName());
                middlePane.addComponent(apiKeyLink);
            }

        }

    }

    public void resetLeftPane() {

        SecurityContext securityContext = ((MifssAdminMainUI) UI.getCurrent()).getSecurityContext();

        String selectedTabIndex = getSelectedTabIndex();

        //
        // clean or create left pane
        if (leftPane == null) {

            leftPane = new VerticalLayout();
            leftPane.setSpacing(true);
            leftPane.setMargin(true);

        } else {
            leftPane.removeAllComponents();
        }

        try {

            //
            // get storages list
            storageDefList = getMifssStorageService().listStorages();

            Label lpTitle = new Label(MifssMessages.getMessage("tile.storage.sets"));
            lpTitle.setStyleName(Runo.LABEL_H1);
            leftPane.addComponent(lpTitle);

            //
            // add new storage set button

            Label horizontalSeparator1 = new Label("<hr/>", ContentMode.HTML);
            leftPane.addComponent(horizontalSeparator1);

            NativeButton addNewStorageSetButton = new NativeButton(MifssMessages.getMessage("title.add.storage.set"));
            addNewStorageSetButton.setWidth("190px");
            addNewStorageSetButton.addClickListener(new OpenNewStorageSetWindowListener(this));
            leftPane.addComponent(addNewStorageSetButton);

            Label horizontalSeparator2 = new Label("<hr/>", ContentMode.HTML);
            leftPane.addComponent(horizontalSeparator2);

            //
            // get list of storage sets and sort it
            storageSetDefList = getMifssStorageService().listStorageSets();
            Collections.sort(storageSetDefList);

            accordion = new Accordion();
            accordion.setHeight(100.0f, Unit.PERCENTAGE);
            int tabCount = 0;

            // create new tab for each storage set
            for (StorageSetDef storageSetDef : storageSetDefList) {

                VerticalLayout accordionLayout = new VerticalLayout();
                accordionLayout.setMargin(true);
                accordionLayout.setSpacing(true);


                String currentUserName = securityContext.getAuthentication().getName();

                // is storage set locked ?
                boolean storageSetDefLocked = storageSetDef.isLocked();
                boolean userCanConfigureStorages = false;

                if (storageSetDefLocked) {

                    //
                    // storage set is locked. Check user name

                    HorizontalLayout lockBar = new HorizontalLayout();
                    lockBar.setSpacing(true);

                    if (storageSetDef.getLockedBy().equals(currentUserName)) {

                        userCanConfigureStorages = true;

                        // add button for lock remove
                        NativeButton unlockButton = new NativeButton(MifssMessages.getMessage("button.storage.set.unlock"));
                        unlockButton.setIcon(new ThemeResource("img/unlocked.png"));
                        UnlockStorageListener unlockStorageListener = new UnlockStorageListener(storageSetDef.getName(), this);
                        unlockButton.addClickListener(unlockStorageListener);
                        lockBar.addComponent(unlockButton);
                        lockBar.setComponentAlignment(unlockButton, Alignment.MIDDLE_LEFT);

                    }

                    //
                    // Display lock information

                    Label lockInfoLabel = new Label(MifssMessages.getMessage("sys.message.storage.set.is.locked.by") + " " + storageSetDef.getLockedBy());
                    lockBar.addComponent(lockInfoLabel);
                    lockBar.setComponentAlignment(lockInfoLabel, Alignment.MIDDLE_RIGHT);
                    accordionLayout.addComponent(lockBar);

                } else {

                    //
                    // Storage set is unlocked. Add button for storage set locking

                    NativeButton lockButton = new NativeButton(MifssMessages.getMessage("button.storage.set.lock"));
                    lockButton.setIcon(new ThemeResource("img/locked.png"));

                    LockStorageSetListener lockStorageSetListener = new LockStorageSetListener(storageSetDef.getName(), this);
                    lockButton.addClickListener(lockStorageSetListener);
                    accordionLayout.addComponent(lockButton);

                }

                // add storage definition links
                for (StorageDef storageDef : storageSetDef.getStorageDefList()) {
                    accordionLayout.addComponent(new StorageDefUiLink(storageDef, this, userCanConfigureStorages));
                }

                accordionLayout.setId("" + tabCount);

                // add tab to accordion
                accordion.addTab(accordionLayout, storageSetDef.getName());
                if (selectedTabIndex != null) {
                    if (accordionLayout.getId().equals(selectedTabIndex)) {
                        accordion.setSelectedTab(accordionLayout);
                    }
                }

                tabCount++;
            }

            leftPane.addComponent(accordion);

        } catch (Exception x) {
            logger.error(x, x);

            ((MifssAdminMainUI) UI.getCurrent()).error(new com.vaadin.server.ErrorEvent(x));

            ExceptionUtils.getStackTrace(x);

            //throw new Exception(x.getMessage(),x);

        }

    }

    public String getSelectedTabIndex() {

        if (accordion != null && accordion.getSelectedTab() != null) {
            return accordion.getSelectedTab().getId();
        } else {
            return null;
        }

    }

    // retrieve storage service
    private StorageService getMifssStorageService() {

        return AppContext.getApplicationContext().getBean(StorageService.class);

    }

    public void resetAllPanes() {

        resetLeftPane();

        if (currentStorageDef != null) {
            for (StorageDef sd : storageDefList) {

                if (sd.getName() == currentStorageDef.getName()) {
                    currentStorageDef = sd;
                    resetMiddlePane(currentStorageDef);
                }
            }

        } else {
            resetMiddlePane(null);
        }

    }

    public StorageDef getCurrentStorageDef() {
        return currentStorageDef;
    }
}
